package com.menghao.rpc.provider.handle.http;

import com.menghao.rpc.RpcConstants;
import com.menghao.rpc.consumer.model.RpcRequest;
import com.menghao.rpc.exception.InvokeException;
import com.menghao.rpc.provider.model.ProviderKey;
import com.menghao.rpc.provider.model.RpcResponse;
import com.menghao.rpc.provider.regisiter.ProviderRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.reflect.Method;
import java.text.MessageFormat;

/**
 * <p>服务提供方统一入口.</br>
 *
 * @author MarvelCode
 */
@RequestMapping("/marvel/rpc/entrance")
public class HttpProviderEntrance {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpProviderEntrance.class);

    private ProviderRepository providerRepository;

    public HttpProviderEntrance(ProviderRepository providerRepository) {
        this.providerRepository = providerRepository;
    }

    @ResponseBody
    @RequestMapping(method = RequestMethod.POST)
    public RpcResponse api(@RequestBody RpcRequest rpcRequest) {
        // 通过 contract、implCode定位服务bean
        ProviderKey providerKey = new ProviderKey(rpcRequest.getContract(), rpcRequest.getImplCode());
        Object bean = providerRepository.getProvider(providerKey);
        if (bean == null) {
            return new RpcResponse(null, new InvokeException(
                    MessageFormat.format("service {0} not found", providerKey)));
        }
        try {
            // 反射调用服务方法
            Method method = ReflectionUtils.findMethod(bean.getClass(), rpcRequest.getMethod(), rpcRequest.getArgsType());
            Object result = ReflectionUtils.invokeMethod(method, bean, rpcRequest.getArgs());
            return new RpcResponse(null, result);
        } catch (Throwable e) {
            LOGGER.error(RpcConstants.LOG_RPC_PREFIX + "invoke exception,", e);
            return new RpcResponse(null, e);
        }
    }
}
